/***************************************************************************
 *   Copyright (C) 2008 by Ivan Blagoev Topolsky   *
 *   ivan.topolsky@genebio.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

// original version by Oliver Evalet (evaleto@genebio.com)
#ifndef __com_util
#define __com_util

#include <ocidl.h>

/**
This file implements a couple of tools that may come handy.
Mostly handling BSTRs and other wide chars
*/


/**
implement our own conversion functions

BSTR are Basic, QuickBasic and Visual Basic -style strings :
- The end isn't marked by a NULL terminator like C strings
- (there's a double NULL at the end anyway)
- The size is indicated in the 32bit word immediately before the data
- As NUL has no special meaning, it can appear in the middle of a Basic String
- (this leading to countless abuses and exploits on Windows platform)

Win32 API provides a series of Sys* functions that properly handles the type 
(including allocating extra space before the start of the string data)

see here :
	http://msdn.microsoft.com/en-us/library/ms221069.aspx
*/


//------------------------//
// Convert char * to BSTR //
//------------------------//

static inline BSTR ConvertStringToBSTR(const char* pSrc)
{
	if(!pSrc) return NULL;

	DWORD cwch;

	BSTR wsOut(NULL);

	if(cwch = ::MultiByteToWideChar(CP_ACP, 0, pSrc, 
	   -1, NULL, 0))//get size minus NULL terminator
	{
		cwch--;
		wsOut = ::SysAllocStringLen(NULL, cwch);

		if(wsOut)
		{
			if(!::MultiByteToWideChar(CP_ACP, 
			      0, pSrc, -1, wsOut, cwch))
			{
				if(ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
					return wsOut;
					::SysFreeString(wsOut);//must clean up
					wsOut = NULL;
			}
		}
	};
	return wsOut;
};


//------------------------//
// Convert BSTR to char * //
//------------------------//
static inline char* ConvertBSTRToString(BSTR pSrc)
{
	if(!pSrc) return NULL;

	//convert even embeded NULL
	DWORD cb,cwch = ::SysStringLen(pSrc);

	char *szOut = NULL;
	if(cb = ::WideCharToMultiByte(CP_ACP, 0, 
	   pSrc, cwch + 1, NULL, 0, 0, 0))
	{
		szOut = new char[cb];
		if(szOut)
		{
			szOut[cb - 1]  = '\0';
			if(!::WideCharToMultiByte(CP_ACP, 0, 
			      pSrc, cwch + 1, szOut, cb, 0, 0))
			{
				delete []szOut;//clean up if failed;

				szOut = NULL;
			}
		}
	}
	return szOut;
};

/**
Wide char string operations for printing, etc.
*/

#ifndef _MSC_VER // MSVC doesn't need this one
static inline std::ostream& operator<<(std::ostream& out, const wchar_t *sp){
	if (sp != NULL)
		while (*sp)	// 'NUL' is the last
			out << (char) *(sp++);
	else
		out << "(null)";
	return out;
}
#endif

static inline std::ostream& operator<<(std::ostream& out, BSTR sp){
	if (sp != NULL)
		for (int i = 0; i < SysStringLen(sp); ++i)	// don't stop at 'NUL'
			out << (char) sp[i];
	else
		out << "(null)";
	return out;
}


/*
int     variant_array_lenght     (VARIANT* array);
int     variant_array_get        (VARIANT* array, VARIANT& result, long row);
int     variant_array_is_valid   (VARIANT * array);
HRESULT ConvertBStrToAnsiStr     (WCHAR* bstrIn, LPSTR * lpszOut);
*/
#endif
